﻿/// <reference path="jquery-1.8.3.js" />
/// <reference path="gzy.menu.js" />
/// <reference path="gzy.drag.js" />
/// <reference path="config.js" />

jQuery.new = function (selector, formatObject) {
    var tagR = /^(\w+)/, idR = /#(\w+)/, clsR = /\.(\w+)/g, attrR = /@(\w+)(?:\((.+?)\))?/g, innerR = /:(?:\((.+?)\))?/;
    if (formatObject) selector = selector.replace(/{(.+?)}/g, function (all, x) { with (formatObject) return eval(x) });
    var result = selector.split('+').map(function (expression, index) {
        var string = '<', tag = 'div', cls = [];
        tagR.test(expression) ? (expression = expression.replace(tagR, function (all, x) { string += x; return '' })) : (string += tag);
        expression = expression.replace(idR, function (all, x) { string += ' id="' + x + '"'; return '' });
        expression = expression.replace(attrR, function (all, x, y) { string += ' ' + x + '="' + (y || x) + '"'; return '' });
        expression = expression.replace(clsR, function (all, x) { cls.push(x); return ''; });
        if (cls.length) string += ' class="' + cls.join(' ') + '"';
        return string + (expression.match(innerR) ? '>' + RegExp.$1 + '</' + tag + '>' : '/>');
    });
    return $(result.join(''));
};
jQuery.fn.insert = function (selector, formatObject) {
    return this.append(jQuery.new(selector, formatObject));
};
jQuery.fn.removeClasses = function () {
    var me = this;
    $.each(arguments, function (i, value) { me.removeClass(value) });
    return this;
}
Array.prototype.remove = function (object) {
    var found = null,
        callback = object instanceof Function ? object : function (x) { return x === object };

    for (var i = 0, a; i < this.length; i++) {
        if (callback(this[i], i)) {
            found = this[i];
            for (; i < this.length;) this[i] = this[++i];
            this.length--;
            break;
        }
    }
    return found;
};
Array.prototype.removeAt = function (index) {
    return this.remove(function (item, i) { return i == index });
}
Array.prototype.find = function (filter) {
    for (var i = 0; i < this.length; i++) {
        if (filter(this[i], i) === true) return this[i];
    }
};
Array.prototype.findApp = function (appid) {
    for (var i = 0; i < this.length; i++) {
        if (this[i].appid == appid) return this[i];
    }
};
Array.prototype.removeApp = function (appid) {
    return this.remove(function (item) { return item.appid == appid });
}
Array.prototype.indexOfApp = function (appid) {
    for (var i = 0; i < this.length; i++) if (this[i].appid == appid) return i;
    return -1;
}
Object.equals = function (object1, object2) {
    for (var key in object1) if (object1.hasOwnProperty(key)) if (!object2.hasOwnProperty(key) || object1[key] !== object2[key]) return false;
    for (var key in object2) if (object2.hasOwnProperty(key)) if (!object1.hasOwnProperty(key) || object1[key] !== object2[key]) return false;
    return true;
}

var QPlus = (function (win, doc, $) {
    "use strict";
    //#region 本地数据存储 localStorage
    var localStorage = window.localStorage || {
        getItem: function (key) {
            var arr = document.cookie.match(new RegExp("(^| )" + key + "=([^;]*)(;|$)"));
            return arr != null ? decodeURIComponent(arr[2]) : null;
        },
        setItem: function (key, data) {
            var expire = data === null ? -1 : 7, exdate = new Date();
            exdate.setTime(exdate.getTime() + (expire * 24 * 60 * 60 * 1000));
            expire = ';expires=' + exdate.toUTCString();
            document.cookie = [key, '=', encodeURIComponent(data === null ? '' : data), expire].join('');
        },
        removeItem: function (key) {
            localStorage.setItem(key, null);
        }
    };
    //#endregion
    //#region 默认配置
    var config = 'q.web.config' in localStorage ? JSON.parse(localStorage.getItem('q.web.config')) : defaultConfig;
    var saveConfig = (function (delay) {
        var timer = 0;
        return function () {
            clearTimeout(timer);
            timer = setTimeout(function () {
                console.log('config saved at ' + new Date().valueOf());
                localStorage.setItem('q.web.config', JSON.stringify(config));
            }, delay);
        }
    })(26);
    //#endregion
    //#region 句柄相关 Handlers
    var Handlers = {
        add: function (object) {
            var handler = new Date().valueOf() + ('#' + Math.random()).replace('0.', '');
            Handlers[handler] = object;
            return handler;
        },
        remove: function (handler) {
            delete Handlers[handler];
        }
    };
    //#endregion
    //#region 桌面 Desktop
    var desktop;
    var currentScreen;
    function Desktop() {
        /// <summary>桌面</summary>
        desktop = this;
        this.theme = new Theme(config.theme);
        this.screens = [];
        config.screens.forEach(function (item) { desktop.screens.push(new Screen(item)) });
        this.switcher = new Switcher(this);
        //this.currentScreenIndex = config.currentScreenIndex;
        this.launcher = new QuickLauncher(config.launcher);
    }
    Desktop.prototype = {
        init: function () {
            var me = this, body = $(doc.body);
            //#region 渲染背景
            $.new('#background').appendTo(body);
            Interface.setTheme(this.theme);
            //#endregion
            //#region 渲染快速启动栏
            this.launcher.ui.appendTo(body).on('dragover', function (e) {
                if (e.target == this) {
                    if (DragEvent.From.fromDesktop || DragEvent.From.fromFolder) {
                        this.classList.add('dragover');
                        e.originalEvent.preventDefault();
                    }
                }
            }).on('dragleave', function () {
                this.classList.remove('dragover');
            }).on('drop', function (e) {
                if (!$(e.target).is('div#launcher'))
                    return this.classList.remove('dragover');

                e.originalEvent.preventDefault();
                var f = DragEvent.Data.ui.parent(),
                    o = DragEvent.Data.destory();

                desktop.launcher.addItem(o);
                //config.launcher.items.push(o);
                //var icon = new AppIcon(o);
                //desktop.launcher.items.push(icon);
                //icon.appendTo(me.launcher.ui);

                if (DragEvent.From.fromDesktop) {
                    //currentScreen.items.remove(DragEvent.Data);
                    //config.screens[config.currentScreenIndex].items.remove(function (x) { return x.appid == DragEvent.Data.appid });
                    //currentScreen.layout();
                    currentScreen.removeItem(o);
                }
                if (DragEvent.From.fromFolder) {
                    currentScreen.items.forEach(function (icon, i) {
                        if (icon.id == DragEvent.From.fromFolder) {
                            var items = config.screens[config.currentScreenIndex].items;
                            items[i].items.remove(function (item, k) { return item.appid === o.appid; });

                            if (items[i].items.length == 0) {
                                items.remove(function (item, k) { return k == i });
                                currentScreen.items.remove(function (item, k) { return k == i }).ui.remove();
                                currentScreen.layout();
                                f.remove();
                            }
                        }
                    });
                }
                saveConfig();
            });
            //#endregion
            //#region 生成分屏和分屏切换器
            var screens = $.new('#screens').appendTo($.new('#screensPanel.' + config.launcher.dock).appendTo(body));
            var switcher = this.switcher.appendTo($.new('#switcher.' + config.launcher.dock).appendTo(body));
            this.screens.forEach(function (item, i) {
                var scr = item.appendTo(screens);
                scr.layout(screens.innerWidth(), screens.innerHeight());
                switcher.append(scr, i);
                if (i == config.currentScreenIndex) {
                    scr.ui.fadeIn('slow');
                    scr.switchButton.addClass('current');
                    currentScreen = scr;
                }
            });
            //#endregion
            //#region 窗口resize时重新布局图标
            var timer;
            $(win).resize(function () {
                clearTimeout(timer);
                timer = setTimeout(function () {
                    me.screens.forEach(function (item, i) {
                        item.layout(screens.innerWidth(), screens.innerHeight());
                    });
                }, 130);
            });
            //#endregion
            //#region 右键菜单处理
            new gzy.menu({
                '#switcher span.current': {
                    items: [{
                        text: '删除当前桌面',
                        enable: function () { return config.screens.length > 1 },
                        command: function () {
                            var d = config.currentScreenIndex, to = d ? d - 1 : d + 1;

                            var removed = desktop.screens[d];
                            config.screens.removeAt(d);

                            removed.items.forEach(function (item, i) {
                                desktop.screens[to].addItem(item.destory());
                            });

                            switcher.goto(to);
                            switcher.ui.children().each(function (i, span) { span.innerHTML = i });

                            removed.ui.remove();
                            removed.switchButton.remove();
                            desktop.screens.removeAt(d);

                            saveConfig();
                        }
                    }]
                },
                '#launcher': { //快速启动栏菜单
                    itemCommand: function (cmdArg, e) {
                        saveConfig(config.launcher.dock = cmdArg);
                        screens.add(launcher).add('#switcher,#screensPanel').removeAttr('class').addClass(cmdArg);
                    }, items: [{ text: '左侧', cmdArg: 'left', enable: function () { return config.launcher.dock != 'left' } }, { text: '上边', cmdArg: 'top', enable: function () { return config.launcher.dock != 'top' } }, { text: '右侧', cmdArg: 'right', enable: function () { return config.launcher.dock != 'right' } }]
                },
                '#launcher .appicon': { //快速启动图标菜单
                    onopen: function () { this.target.addClass('hover') },
                    onclose: function () { this.target.removeClass('hover') },
                    items: [{
                        text: '从快速启动栏移除', command: function () {
                            var app = Handlers[this.target.data('s')];
                            me.launcher.removeItem(app);
                            currentScreen.addItem(app);
                        }
                    }]
                },
                '.screen': { //桌面菜单
                    items: [{
                        text: '主题设置',
                        command: function () { Progress.start('system://themes') }
                    }]
                },
                '.screen .appicon': { //桌面图标菜单
                    onopen: function () {
                        this.target.addClass('hover');
                        var items = [];
                        for (var i = 0; i < config.screens.length; i++) items.push({ text: '第' + (i + 1) + '屏', cmdArg: i, enable: i != config.currentScreenIndex });
                        items.push('-', { text: 'NEW', cmdArg: -1 });
                        this.items[0].items = items;
                    },
                    onclose: function () { this.target.removeClass('hover') },
                    items: [{
                        text: '移动至：', itemCommand: function (cmdArg) {
                            var icon = Handlers[this.target.data('s')].destory();
                            if (cmdArg == -1) {
                                var item = { items: [] };
                                config.screens.push(item);
                                saveConfig();
                                var scr = new Screen(item).appendTo(screens);
                                scr.layout(screens.innerWidth(), screens.innerHeight());
                                switcher.append(scr, cmdArg = desktop.screens.length);
                                desktop.screens.push(scr);
                            }

                            currentScreen.removeItem(icon);
                            me.screens[cmdArg].addItem(icon);

                            var tip = $.new('.tip:(“' + icon.name + '”已移至第 ' + (cmdArg + 1) + ' 屏)').appendTo('body').click(function () {
                                me.switcher.goto(cmdArg);
                                tip.stop().fadeOut();
                            }).delay(3000).fadeOut(function () { tip.remove() });
                        }
                    }, {
                        text: '重命名', command: function () {
                            var icon = Handlers[this.target.data('s')];
                            icon.ui.addClass('editing').attr('draggable', false);
                            var span = icon.ui.find('span');
                            var input = $.new('input').appendTo(span.empty()).val(icon.name).select().change(function () {
                                icon.name = input.val();
                                currentScreen.config.items.find(function (item) { return item.appid == icon.appid }).name = icon.name;
                                saveConfig();
                            }).blur(function cancelEdit() {
                                icon.ui.removeClasses('editing', 'hover').attr('title', icon.name).attr('draggable', true);
                                span.text(icon.name);
                            }).keydown(function (e) {
                                if (e.keyCode == 27 || e.keyCode == 13) this.blur();
                            });
                        }
                    }, {
                        text: '卸载应用',
                        enable: function () { return Handlers[this.target.data('s')].items === null },
                        command: function () {
                            var icon = Handlers[this.target.data('s')];
                            Interface.uninstall(icon);
                        }
                    }]
                },
                //'.folder .appicon': {
                //      text: '文件夹中的图标菜单，暂未实现。'
                //},
                '.tbbutton': { //任务栏按钮菜单
                    target: '.tbbutton',
                    onopen: function () { this.target.addClass('hover') },
                    onclose: function () { this.target.removeClass('hover') },
                    itemCommand: function (cmdArg, e) { Handlers[this.target.data('winid')][cmdArg](); },
                    items: [
                        { text: '最大化', cmdArg: 'maximize', enable: function () { var win = Handlers[this.target.data('winid')]; return win.resizable && win.state != Window.state.maximize } },
                        { text: '最小化', cmdArg: 'minimize', enable: function () { return Handlers[this.target.data('winid')].state != Window.state.minimize } },
                        { text: '还原', cmdArg: 'restore', enable: function () { return Handlers[this.target.data('winid')].state != Window.state.normal } },
                        '-',
                        { text: '关闭', cmdArg: 'close' }
                    ]
                }
            });
            //#endregion
            return this;
        }
    };
    //#endregion
    //#region 主题 Theme
    function Theme(options) {
        /// <summary>主题</summary>
        $.extend(this, { bgImage: '', themeId: 0, position: 'stretch' }, options);
    }
    Theme.picker = function () {
        Window.open({ name: '主题设置', icon: 'pngs/art.png' }, {
            url: 'themes.html',
            resizable: false
        });
    }
    //#endregion
    //#region 多屏切换 Switcher
    function Switcher(desktop) {
        /// <summary>分屏切换器</summary>
        $.extend(this, { ui: $.new('div') });

        this.appendTo = function (container) {
            var me = this;
            this.ui.appendTo(container).click(function (e) {
                var clicked = $(e.target);
                if (clicked.is('span')) {
                    me.goto(parseInt(clicked.text()));
                }
            });
            return this;
        };
        this.append = function (scr, index) {
            scr.switchButton.text(index).appendTo(this.ui);
        };
        this.goto = function (index) {
            currentScreen = desktop.screens[index];
            config.currentScreenIndex = index;
            var siblings = currentScreen.ui.siblings();
            siblings.length ? siblings.fadeOut(function () { currentScreen.ui.fadeIn() }) : currentScreen.ui.fadeIn();
            this.ui.children().removeClass('current');
            this.ui.children(':eq(' + index + ')').addClass('current');
            saveConfig();
        }
    }
    //#endregion
    //#region 分屏 Screen
    function Screen(options) {
        /// <summary>一个分屏</summary>
        this.taskbar = new TaskBar();
        this.items = [];
        options.items.forEach(function (item, i) { this.items.push(new AppIcon(item)) }, this);
        this.itemMargin = options.itemMargin;
        this.ui = $.new('.screen');
        this.switchButton = $.new('span');
        this.width = this.width = 0;
        this.config = options;
    }
    Screen.prototype = {
        addItem: function (item) {
            this.config.items.push(item);
            var icon = new AppIcon(item);
            this.items.push(icon);
            icon.appendTo(this.ui);
            this.layout();
            saveConfig();
        },
        removeItem: function (item) {
            Handlers.remove(item);
            if (item.ui) item.destory();
            this.items.removeApp(item.appid);
            this.config.items.removeApp(item.appid);
            this.layout();
            saveConfig();
        },
        appendTo: function (container) {
            var scr = this.ui.appendTo(container);
            this.items.forEach(function (item, i, array) {
                item.appendTo(scr);
            });
            this.taskbar.appendTo(scr);
            this.id = Handlers.add(this);

            this.ui.on('dragover', function (e) {
                if (e.target == this) {
                    if (DragEvent.From.fromFolder || DragEvent.From.fromLauncher) {
                        this.classList.add('dragover');
                        e.originalEvent.preventDefault();
                    }
                }
            }).on('dragleave', function (e) {
                this.classList.remove('dragover');
            }).on('drop', function (e) {
                if (e.target !== this) return;
                this.classList.remove('dragover');
                e.originalEvent.preventDefault();
                var icon = DragEvent.Data.destory();

                if (DragEvent.From.fromLauncher) {
                    //config.launcher.items.removeApp(icon.appid);
                    //desktop.launcher.items.removeApp(icon.appid);
                    desktop.launcher.removeItem(icon);
                }
                if (DragEvent.From.fromFolder) {
                    var from = Handlers[DragEvent.From.fromFolder];
                    from.items.removeApp(icon.appid);
                    from.config.items.removeApp(icon.appid);

                    if (from.items.length == 0) {
                        from.destory();
                        $('.folder').remove();
                        if (currentScreen.items.findApp(from.appid)) {
                            //currentScreen.items.removeApp(from.appid);
                            //currentScreen.config.items.removeApp(from.appid);
                            currentScreen.removeItem(from);
                        }
                        if (desktop.launcher.items.findApp(from.appid)) {
                            //desktop.launcher.items.removeApp(from.appid);
                            //config.launcher.items.removeApp(from.appid);
                            desktop.launcher.removeItem(from);
                        }
                    }
                }
                //currentScreen.config.items.push(icon);
                //saveConfig();
                //var newcc = new AppIcon(icon);
                //currentScreen.items.push(newcc);
                //newcc.appendTo(currentScreen.ui);
                //currentScreen.layout();
                currentScreen.addItem(icon);
            });
            return this;
        },
        layout: function (width, height) {
            var x = 0, y = 0, m = 30, h = height ? this.height = height : this.height, w = width ? this.width = width : this.width;
            this.items.forEach(function (item, i) {
                var top = m + y * (77 + m);
                item.ui.css({ left: m + x * (77 + m), top: top });
                top + 77 + m + 77 > h - 77 ? (x++, y = 0) : y++;
            });
        }
    };
    //#endregion
    //#region 快速启动 QuickLauncher
    function QuickLauncher(options) {
        /// <summary>快速启动栏</summary>
        var me = this;
        this.ui = $.new('#launcher.' + options.dock);
        this.items = [];

        config.launcher.items.forEach(function (item, i) {
            var icon = new AppIcon(item);
            icon.appendTo(me.ui);
            me.items[i] = icon;
        });

        this.addItem = function (item) {
            var icon = new AppIcon(item);
            icon.appendTo(me.ui);
            me.items.push(icon);
            config.launcher.items.push(item);
            saveConfig();
        };
        this.removeItem = function (item) {
            Handlers.remove(item);
            if (item.ui) item.destory();
            me.items.removeApp(item.appid);
            config.launcher.items.removeApp(item.appid);
            saveConfig();
        }
    }
    //#endregion
    //#region 任务栏 TaskBar
    function TaskBar() {
        this.ui = $.new('.taskbar');
    }
    TaskBar.prototype = {
        appendTo: function (container) {
            this.ui.appendTo(container);
        },
        add: function (thewin) {
            return new TaskBarButton(thewin).appendTo(this.ui);
        }
    };
    //#endregion
    //#region 拖动事件代理 DragEvent
    if (!DragEvent) var DragEvent = {};
    DragEvent.From = { fromDesktop: false, fromLauncher: false, fromFolder: false };
    DragEvent.Data = null;
    //#endregion
    //#region 快捷方式 AppIcon
    function AppIcon(options) {
        /// <summary>快捷方式</summary>
        $.extend(this, { src: '', icon: '', name: '', }, options);
        this.config = options;
    }
    AppIcon.prototype = {
        destory: function () {
            this.ui && this.ui.remove();
            delete Handlers[this.id]; delete this.id; delete this.ui; delete this.config;
            return this;
        },
        appendTo: function (container) {
            this.id = Handlers.add(this);
            var me = this;
            this.ui = $.new('.appicon@title({name})@draggable(true)', this).insert('img@draggable(false)@src({icon})+span:({name})', this).on('dragstart', function (e) {
                $.extend(DragEvent.From, {
                    fromDesktop: container.is('div.screen') ? currentScreen.id : false,
                    fromLauncher: container.is('#launcher'),
                    fromFolder: container.is('div.folder') ? $('.hover').data('s') : false
                });
                DragEvent.Data = me;
            }).on('dragover', function (e) {
                if (DragEvent.Data.ui[0] !== this) {
                    var me = Handlers[$(this).data('s')];
                    if ((DragEvent.Data.items && !me.items)
                        || $(this).is('.folder div')
                        || (me.items && me.items.findApp(DragEvent.Data.appid))) return;
                    this.classList.add('dragover');
                    e.originalEvent.preventDefault();
                }
            }).on('dragleave', function () {
                this.classList.remove('dragover');
            }).on('drop', function (e) {
                if (DragEvent.Data.items && !Handlers[$(this).data('s')].items) return;
                e.originalEvent.preventDefault();
                this.classList.remove('dragover');
                var icon = DragEvent.Data.destory(),
                    to = Handlers[$(this).data('s')];

                //#region 删除原图标的注册
                if (DragEvent.From.fromDesktop) {
                    //currentScreen.items.remove(icon);
                    //currentScreen.config.items.removeApp(icon.appid);
                    currentScreen.removeItem(icon);
                } else if (DragEvent.From.fromLauncher) {
                    //desktop.launcher.items.removeApp(icon.appid);
                    //config.launcher.items.removeApp(icon.appid);
                    desktop.launcher.removeItem(icon);
                } else if (DragEvent.From.fromFolder) {
                    var from = Handlers[DragEvent.From.fromFolder];
                    from.items.removeApp(icon.appid);
                    from.config.items.removeApp(icon.appid);
                    if (from.items.length == 0) {
                        from.destory();
                        $('.folder').remove();
                        if (currentScreen.items.findApp(from.appid)) {
                            //currentScreen.items.removeApp(from.appid);
                            //currentScreen.config.items.removeApp(from.appid);
                            currentScreen.removeItem(from);
                        }
                        if (desktop.launcher.items.findApp(from.appid)) {
                            //desktop.launcher.items.removeApp(from.appid);
                            //config.launcher.items.removeApp(from.appid);
                            desktop.launcher.removeItem(from);
                        }
                    }
                }
                //#endregion
                //#region 生成新图标
                if (to.items) { //目标位置是文件夹
                    !!icon.items ? Array.prototype.push.apply(to.config.items, icon.items) : to.config.items.push(icon);
                } else { //目标位置是快捷图标，须把目标位置替换成文件夹，再把两个图标依次放进去
                    var newF = { name: '文件夹', icon: 'pngs/package.png', appid: 'F' + new Date().valueOf(), items: [to.destory(), icon] };
                    if (currentScreen.items.findApp(to.appid)) {
                        var i = currentScreen.items.indexOfApp(to.appid);
                        currentScreen.config.items[i] = newF;
                        currentScreen.items[i] = new AppIcon(newF);
                        currentScreen.items[i].appendTo(currentScreen.ui);
                    }
                    if (config.launcher.items.findApp(to.appid)) {
                        var i = desktop.launcher.items.indexOfApp(to.appid);
                        config.launcher.items[i] = newF;
                        new AppIcon(newF).appendTo(desktop.launcher.ui);
                    }
                }
                //#endregion

                saveConfig();
                currentScreen.layout();
            });
            this.ui.click(function (e) {
                if (me.ui.hasClass('editing')) return;
                var app = Handlers[$(this).data('s')];
                if (app.items === null) {
                    Progress.start(me);
                } else if (app.items instanceof Array) {
                    var ef = $(this).addClass('hover'), folder = $.new('.folder').appendTo('body').moveTo(e.pageX - 2, e.pageY - 2).fadeTo('fast', 1);
                    folder.mouseleave(function () { ef.removeClass('hover'), folder.remove() });
                    app.items.forEach(function (item) { new AppIcon(item).appendTo(folder) });
                }
            }).data('s', this.id);
            return this.ui.appendTo(container);
        }
    };
    //#endregion
    //#region 窗口 Window
    var Window = {
        state: { normal: 1, minimize: 2, maximize: 3 },
        list: [],
        zIndex: 1000,
        open: function (icon, options) {
            var winc, wtbar, wtitle, tools, wbody, wcmds, control, control_minimize, control_maximize, control_restore, control_close;
            //#region 创建元素结构
            winc = $.new('.window').css({ zIndex: Window.zIndex++ });
            wtbar = $.new('h4.tbar').appendTo(winc);
            wtitle = $.new('label:(' + icon.name + ')').appendTo(wtbar);
            tools = $.new('span.tools').appendTo(wtbar);
            wbody = $.new('.body').appendTo(winc);
            wcmds = $.new('.cmds').appendTo(winc);
            //#endregion
            //#region 最大最小化还原关闭
            control = $.new('span.control').appendTo(wtbar);
            control.append(control_minimize = $.new('b.minimize@title(最小化)').click(minimize));
            if (options.resizable !== false) {
                control.append(control_maximize = $.new('b.maximize@title(最大化)').click(maximize));
                control.append(control_restore = $.new('b.restore@title(向下还原)').click(restore));
            }
            control.append(control_close = $.new('b.close@title(关闭)').click(close));
            //#endregion
            //#region 重设大小控制
            var resize_n, resize_e, resize_s, resize_w, resize_nw, resize_ne, resize_se, resize_sw;
            if (options.resizable !== false) {
                resize_n = $.new('.resize.n').appendTo(winc).mousedown(function (e) {
                    var p, h;
                    new gzy.drag(e, resize_n, true, {
                        lockY: true,
                        init: function (module, handle) { p = winc.position(), h = winc.height(), handle.css({ height: '+=400', top: '-=200' }) },
                        ondrag: function (e, sl) { return !winc.css({ top: sl.top + p.top + 2, height: h - sl.top - 2 }) },
                        onstop: function (e, module, handle) { handle.css({ height: '', top: '' }) }
                    });
                });
                resize_e = $.new('.resize.e').appendTo(winc).mousedown(function (e) {
                    new gzy.drag(e, resize_e, true, {
                        lockY: true,
                        init: function (module, handle) { handle.css({ width: '+=400', right: '-=200' }) },
                        ondrag: function (e, sl) { return !winc.css({ width: sl.left + 2 }) },
                        onstop: function (e, module, handle) { handle.css({ width: '', right: '' }) }
                    });
                });
                resize_s = $.new('.resize.s').appendTo(winc).mousedown(function (e) {
                    new gzy.drag(e, resize_s, true, {
                        lockX: true,
                        init: function (module, handle) { handle.css({ height: '+=400', bottom: '-=200' }) },
                        ondrag: function (e, sl) { return !winc.css({ height: sl.top + 2 }) },
                        onstop: function (e, module, handle) { handle.css({ height: '', bottom: '' }) }
                    });
                });
                resize_w = $.new('.resize.w').appendTo(winc).mousedown(function (e) {
                    var p, w;
                    new gzy.drag(e, resize_w, true, {
                        lockY: true,
                        init: function (module, handle) { p = winc.position(), w = winc.width(), handle.css({ width: '+=400', left: '-=200' }) },
                        ondrag: function (e, sl) { return !winc.css({ left: sl.left + p.left + 2, width: w - sl.left - 2 }) },
                        onstop: function (e, module, handle) { handle.css({ width: '', left: '' }) }
                    });
                });
                resize_nw = $.new('.resize.nw').appendTo(winc).mousedown(function (e) {
                    var p, w, h;
                    new gzy.drag(e, resize_nw, true, {
                        init: function (module, handle) { p = winc.position(), w = winc.width(), h = winc.height(), handle.css({ width: '+=400', height: '+=400', left: '-=200', top: '-=200' }) },
                        ondrag: function (e, sl) { return !winc.css({ top: sl.top + p.top + 2, left: sl.left + p.left + 2, width: w - sl.left - 2, height: h - sl.top - 2 }) },
                        onstop: function (e, module, handle) { handle.css({ width: '', height: '', left: '', top: '' }) }
                    });
                });
                resize_ne = $.new('.resize.ne').appendTo(winc).mousedown(function (e) {
                    var p, h;
                    new gzy.drag(e, resize_ne, true, {
                        init: function (module, handle) { p = winc.position(), h = winc.height(), handle.css({ width: '+=400', height: '+=400', right: '-=200', top: '-=200' }) },
                        ondrag: function (e, sl) { return !winc.css({ top: sl.top + p.top + 2, height: h - sl.top - 2, width: sl.left + 2 }) },
                        onstop: function (e, module, handle) { handle.css({ width: '', height: '', right: '', top: '' }) }
                    });
                });
                resize_se = $.new('.resize.se').appendTo(winc).mousedown(function (e) {
                    new gzy.drag(e, resize_se, true, {
                        init: function (module, handle) { handle.css({ width: '+=400', height: '+=400', right: '-=200', bottom: '-=200' }) },
                        ondrag: function (e, sl) { return !winc.css({ height: sl.top + 2, width: sl.left + 2 }) },
                        onstop: function (module, handle) { handle.css({ width: '', height: '', right: '', bottom: '' }) }
                    });
                });
                resize_sw = $.new('.resize.sw').appendTo(winc).mousedown(function (e) {
                    var p, w;
                    new gzy.drag(e, resize_sw, true, {
                        init: function (module, handle) { p = winc.position(), w = winc.width(), handle.css({ width: '+=400', height: '+=400', left: '-=200', bottom: '-=200' }) },
                        ondrag: function (e, sl) { return !winc.css({ height: sl.top + 2, left: sl.left + p.left + 2, width: w - sl.left - 2 }) },
                        onstop: function (module, handle) { handle.css({ width: '', height: '', left: '', bottom: '' }) }
                    });
                });
            }
            //#endregion
            //#region 初始位置和大小
            winc.appendTo('body');
            var loc = { left: parseInt(win.innerWidth / 2) - 300, top: parseInt(win.innerHeight / 2) - 200, width: 600, height: 400 };
            if (options.left) loc.left = options.left;
            if (options.top) loc.top = options.top;
            if (options.width) loc.width = options.width;
            if (options.height) loc.height = options.height;
            winc.css(loc);
            //#endregion

            winc.mousedown(active);
            wtbar.drag(winc, {
                box: win,
                init: function () { wbody.hide(); winc.fadeTo('fast', .7) },
                onstop: function () { wbody.fadeIn(); winc.fadeTo('fast', 1); }
            });

            //#region 窗口事件处理
            function close() {
                console.log('close');
                winc.animate({ top: '-=6', left: '-=6', width: '+=12', height: '+=12', opacity: 0 }, 'fast', function () {
                    winc.remove();
                    thewin.taskButton.remove();
                    Window.list.remove(thewin);
                    Handlers.remove(thewin.id);
                });
            }
            function maximize() {
                console.log('maximize');
                var p, dest, ani;
                if (thewin.state == Window.state.normal) {
                    p = winc.offset();
                    loc = { left: p.left, top: p.top, width: winc.width(), height: winc.height() };
                }
                if (thewin.state == Window.state.minimize) {
                    p = thewin.taskButton.ui.offset();
                }
                dest = { left: 0, top: 0, width: '100%', height: '100%' };
                ani = $.new('.winani').css({ left: p.left, top: p.top, width: winc.width(), height: winc.height() }).appendTo('body').animate(dest, 'fast', function () {
                    winc.css(dest).show();
                    ani.remove();
                    winc.find('.resize').hide(), control_maximize.fadeOut(function () { control_restore.fadeIn() });
                });
                thewin.state = Window.state.maximize;
            }
            function restore() {
                console.log('restore');
                if (thewin.state == Window.state.maximize) {
                    $.new('.winani').appendTo('body').animate(loc, 'fast', function () {
                        winc.css(loc);
                        $(this).remove();
                        winc.find('.resize').show(), control_restore.fadeOut(function () { control_maximize.fadeIn() });
                        console.log('from maximize');
                    });
                }
                if (thewin.state == Window.state.minimize) {
                    var dp = thewin.taskButton.ui.offset();
                    var dest = { left: dp.left, top: dp.top, width: thewin.taskButton.ui.outerWidth(), height: thewin.taskButton.ui.outerHeight() };
                    $.new('.winani').css(dest).appendTo('body').animate(loc, 'fast', function () {
                        $(this).remove();
                        console.log('from minimize');
                        thewin.state = loc.state;
                    });
                    winc.fadeIn('fast');
                    Window.active(thewin);
                }
                thewin.state = Window.state.normal;
            }
            function minimize() {
                console.log('minimize');
                var p = winc.offset();
                if (thewin.state == Window.state.normal)
                    loc = { left: p.left, top: p.top, width: winc.width(), height: winc.height() };
                loc.state = thewin.state;

                var dp = thewin.taskButton.ui.offset();
                var dest = { left: dp.left, top: dp.top, width: thewin.taskButton.ui.outerWidth(), height: thewin.taskButton.ui.outerHeight() };
                $.new('.winani').css(loc).appendTo('body').animate(dest, 'fast', function () {
                    $(this).remove();
                });
                winc.fadeOut('fast');
                thewin.state = Window.state.minimize;
                Window.active(null);
                var law = Window.list.find(function (x, i) { return x.state != Window.state.minimize });
                if (law) Window.active(law);
            }
            function active() {
                Window.active(thewin);
            }
            //#endregion
            function setContent(content) {
                /// <summary>设置窗口中显示的内容</summary>
                if (content.url) {
                    var iframe = $.new('iframe@src({url})@frameborder(0)@width(100%)@height(100%)', content).appendTo(wbody);
                    iframe[0].contentWindow.parentWindow = thewin;
                    iframe.load(function () {
                        this.contentWindow.parentWindow = thewin;
                        if (this.contentDocument.title) setTitle(this.contentDocument.title);
                        $(this.contentDocument.documentElement).mousedown(function () {
                            Window.active(thewin);
                        });
                        options.loaded && options.loaded();
                    });
                    return;
                }
                if (content.html) {
                    wbody.append(content.html);
                }
                options.loaded && options.loaded();
            }
            function setTitle(title) {
                wtitle.text(title);
                thewin.taskButton.ui.find('label').text(title);
            }
            var thewin = {
                ui: winc,
                state: Window.state.normal,
                icon: icon,
                resizable: options.resizable != false,
                close: close,
                maximize: maximize,
                restore: restore,
                minimize: minimize,
                setContent: setContent,
                setTitle: setTitle,
                top: currentScreen,
                api: Interface
            };
            thewin.id = Handlers.add(thewin);
            thewin.taskButton = currentScreen.taskbar.add(thewin);
            Window.list.unshift(thewin);
            Window.active(thewin);

            setContent(options);

            return thewin;
        },
        active: function (thewin) {
            Window.list.forEach(function (x, i) {
                if (x.active) {
                    x.ui.removeClass('active');
                    x.active = false;
                    x.taskButton && x.taskButton.ui.removeClass('active');
                }
            });
            if (thewin) {
                thewin.ui.addClass('active').css({ zIndex: Window.zIndex++ });
                thewin.active = true;
                thewin.taskButton && thewin.taskButton.ui.addClass('active');
            }
        }
    };
    //#endregion
    //#region 窗口小工具 WindowTool
    function WindowTool() {

    }
    //#endregion
    //#region 任务栏按钮 TaskBarButton
    function TaskBarButton(thewin) {
        this.win = thewin;
        this.ui = $.new('.tbbutton');
        this.ui.data('winid', thewin.id);
        this.id = Handlers.add(this);
    }
    TaskBarButton.prototype = {
        appendTo: function (container) {
            var me = this;
            this.ui.appendTo(container).append($.new('img@src({icon})+label:({name})', this.win.icon)).click(function () {
                me.win.state == Window.state.minimize ? me.win.restore() : me.win.active ? me.win.minimize() : Window.active(me.win);
            });
            return this;
        },
        remove: function () {
            this.ui.remove();
            Handlers.remove(this.id);
        }
    };
    //#endregion
    //#region 任务管理 Progress
    var Progress = {
        start: function (uri) {
            var splits = (uri.src || uri).split('://');
            switch (splits[0]) {
                case 'widget':
                    alert(splits[1]);
                    break;

                case 'system':
                    System.execute(splits[1]);
                    break;

                default:
                    Window.open(uri, { url: splits.join('://') });
            }
        }
    };
    //#endregion
    //#region 系统指令 System
    var System = {
        execute: function (cmd) {
            switch (cmd) {
                case 'themes': return Theme.picker();
                case 'createfolder': return System.createFolder();
                default: console.log('unrecogenized command: ' + cmd);
            }
        },
        createFolder: function () {
            debugger;
        }
    };
    //#endregion
    //#region 公共接口 Interface
    var Interface = {
        install: function (app) {
            config.screens[config.currentScreenIndex].items.push(app);
            saveConfig();
            app = new AppIcon(app);
            currentScreen.items.push(app);
            app.appendTo(currentScreen.ui);
            currentScreen.layout();
        },
        uninstall: function (app) {

            for (var i = 0, x; x = config.launcher.items[i]; i++) {
                if (x.items) {
                    for (var j = 0, y; y = x.items[j++];) {
                        if (uninstall.call(config.launcher.items[i].items, y, desktop.launcher.items[i].items)) return saveConfig();
                    }
                } else {
                    if (uninstall.call(config.launcher.items, x, desktop.launcher.items)) return saveConfig();
                }
            }
            for (var i = 0; i < config.screens.length; i++) {
                for (var j = 0; j < config.screens[i].items.length; j++) {
                    if (config.screens[i].items[j].items) {
                        for (var k = 0; k < config.screens[i].items[j].items.length; k++) {
                            if (uninstall.call(config.screens[i].items[j].items, config.screens[i].items[j].items[k], desktop.screens[i].items[j].items)) return saveConfig();
                        }
                    } else {
                        if (uninstall.call(config.screens[i].items, config.screens[i].items[j], desktop.screens[i].items)) return saveConfig();
                    }
                }
            }
            function uninstall(item, items) {
                if (item.appid == app.appid) {
                    this.removeApp(app.appid);
                    var icon = items.removeApp(app.appid);
                    icon instanceof AppIcon && icon.ui.remove();
                    return true;
                }
            }
        },
        test: function (app) {
            var sxt = [].concat(config.launcher.items);
            config.screens.forEach(function (scr) { [].push.apply(sxt, scr.items); });
            for (var i = 0, t; t = sxt[i++];) {
                if (!t.items) {
                    if (t.appid == app.appid) return true;
                } else {
                    for (var k = 0, p; p = t.items[k++];) {
                        if (p.appid == app.appid) return true;
                    }
                }
            }
            return false;
        },
        setTheme: function (theme) {
            var background = $('#background').empty().removeAttr('style');
            switch (theme.position) {
                case 'stretch': background.insert('img@src({bgImage})', theme).fadeTo('fast', 1); break;
                case 'middle': background.css({ background: 'url(' + theme.bgImage + ') no-repeat center center' }).fadeTo('fast', 1); break;
                case 'tile': background.css({ background: 'url(' + theme.bgImage + ') repeat center center' }).fadeTo('fast', 1); break;
            }
            if (!Object.equals(config.theme, theme)) saveConfig(config.theme = theme);
        },
        getTheme: function () {
            return $.extend({}, config.theme);
        }
    };
    //#endregion
    /*@cc_on
    return new Desktop().init();
    @*/
    return new Desktop();
})(window, document, jQuery);